﻿
namespace HSS
{
	#region Using Directives
	using System;
	using System.Linq.Expressions;
	using System.Reflection;
	using HSS.Resources;
	#endregion

	#region PropertyExtensions
	/// <summary>
	/// Misc. extension methods for <see cref="Expression"/>s of a class Property.
	/// </summary>
	public static class PropertyExtensions
	{
		/// <summary>
		/// Processes the provided expression and extracts it's <see cref="MemberExpression"/>
		/// validating that it represents a valid Property.
		/// </summary>
		/// <typeparam name="T">The Type of the Property.</typeparam>
		/// <param name="expression">The expression to process.</param>
		/// <returns>A valid <see cref="MemberExpression"/>.</returns>
		/// <exception cref="ArgumentException">The expression must select a property type.</exception>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
		public static MemberExpression GetPropertyExpression<T>(this Expression<Func<T>> expression)
		{
			Guard.ArgumentNotNull(expression, "expression");
			var body = expression.Body as MemberExpression;
			if (body != null)
			{
				Guard.ArgumentThrowIf(body.Member.MemberType != MemberTypes.Property, "expression", ResourceProvider.GetString(StringKeys.ExpressionMustSelectAProperty));
				return body;
			}
			var expression2 = expression.Body as UnaryExpression;
			if (expression2 != null)
			{
				var operand = expression2.Operand as MemberExpression;
				if (operand != null)
				{
					Guard.ArgumentThrowIf(operand.Member.MemberType != MemberTypes.Property, "expression", ResourceProvider.GetString(StringKeys.ExpressionMustSelectAProperty));
					return operand;
				}
			}
			return null;
		}
		/// <summary>
		/// Processes the provided expression and extracts the Property's Name
		/// validating that it represents a valid Property.
		/// </summary>
		/// <typeparam name="T">The Type of the Property.</typeparam>
		/// <param name="expression">The expression to process.</param>
		/// <returns>The Name of the Property.</returns>
		/// <exception cref="ArgumentException">The expression must select a property type.</exception>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
		public static string GetPropertyName<T>(this Expression<Func<T>> expression)
		{
			Guard.ArgumentNotNull(expression, "expression");
			var body = expression.Body as MemberExpression;
			if (body == null)
			{
				var expression2 = expression.Body as UnaryExpression;
				if (expression2 != null)
					body = expression2.Operand as MemberExpression;
			}
			if (body != null)
			{
				Guard.ArgumentThrowIf(body.Member.MemberType != MemberTypes.Property, "expression", ResourceProvider.GetString(StringKeys.ExpressionMustSelectAProperty));
				return body.Member.Name;
			}
			return null;
		}
	}
	#endregion
}